home *** CD-ROM | disk | FTP | other *** search
/ EuroCD 3 / EuroCD 3.iso / Programming / Amos / AMOSList-0497 / AMOSLIST / Optim_Tips.lha / Optimisation_Tips.txt
Encoding:
Text File  |  1997-04-06  |  13.7 KB  |  473 lines

  1.  
  2. AMOS Code Optimisation Tips
  3. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. Aminet - dev/amos/OptimiseTips.lha
  5.  
  6. Compiled by :
  7.  
  8.    Ben Wyatt       bwyatt@paston.co.uk
  9.  
  10. Contributors :
  11.  
  12.    Ben Wyatt       bwyatt@paston.co.uk
  13.    Paul Hickman    ph@doc.ic.ac.uk
  14.    Tim Lewis       T.Lewis@bton.ac.uk
  15.    Petri Hakkinen  mystic@tlti.tokem.fi
  16.    Mark de Jong    JP.de.Jong@inter.nl.net
  17.    Paul Heald      u5o83@cc.keele.ac.uk
  18.  
  19. Here are a few optimisation tips for those of you trying to squeeze that
  20. little bit more speed out of code. With the follow examples, the speed
  21. increase may not be noticable, but they will all make it that little bit
  22. faster.
  23.  
  24. Important: Do not go through your entire AMOS program collection, converting
  25. all your code so it's slightly faster. Only alter code which you think is
  26. /too/ slow. For example, don't change your 3D renderer just to cut down the
  27. rendering time 1/50 of a second or something silly. And similarly, don't
  28. bother fiddling with the main loop of a game when it already runs in a Vbl!
  29. A lot of these optimisation tips produce some messy code so often it isn't
  30. worth changing things!
  31.  
  32. Note: Some of these speed increases only work when compiled, mainly with
  33. the AMOSPro Compiler. A lot of them are only tested this way.
  34.  
  35. The amount of speed increase is shown by a S, M, L and V under the number of
  36. the tip. These stand for Small, Medium, Large and Varies.
  37.  
  38. 1. Don't use Sgn(n), use n<0 and n>0 instead.
  39. S
  40.    Eg.
  41.       Don't use :
  42.          If Sgn(n)=-1 Then blah blah
  43.          If Sgn(n)=1 Then blah de blah
  44.       Use this instead :
  45.          If n<0 Then blah blah
  46.          If n>0 Then blah de blah
  47.  
  48. 2. For your most used array of 8 (or less) elements, use Dreg() instead of
  49. M  it (it can still hold the same range of values). Note: The Dreg() array
  50.    isn't actually using the data registers; it's an AMOS internal data
  51.    structure. However, it's still faster than a standard array.
  52.  
  53.    Eg.
  54.       Don't use :
  55.          Dim n(7)
  56.          For a=0 to 7:Print n(a):Next a
  57.       Use this instead :
  58.          For a=0 To 7:Print Dreg(a):Next a
  59.  
  60. 3. Use Abs(n)<v instead of n>-v and n<v.
  61. M
  62.    Eg.
  63.       Don't use :
  64.          If n>-5 and n<5 Then blah
  65.       Use this instead :
  66.          If Abs(n)<5 Then blah
  67.  
  68. 4. Whenever possible use powers of 2 when multiplying or dividing. The
  69. L  AMOSPro Compiler will automatically optimise these to lsl and lsr.
  70.    DON'T use the lsl or lsr commands in extensions, as they are over
  71.    TWICE as slow!
  72.  
  73.    Eg.
  74.       Don't use :
  75.          n=a*30
  76.       Use this instead (if suitable) :
  77.          n=a*32
  78.  
  79.    As well as this, you can also do :
  80.       n=x*160 -> n=x*(128+32) -> n=x*128+x*32 (tadaa)
  81.       Also n=x*192 -> n=x*128+x*64 etc.
  82.  
  83.    But, this kind of thing is not faster:
  84.       a=32 : b=7
  85.       c=a*b
  86.  
  87. 5. Predefine as much as possible. Especially useful for Sin and Cos etc.
  88. L
  89.    Eg.
  90.       Don't use :
  91.          Repeat
  92.             If Sqr(x*x+y*y)=10 Then blah blah blah
  93.          Until Something
  94.       Use this instead :
  95.          xmax=Maximum value of x : ymax=Maximum value of y
  96.          Dim QUICKSQR(xmax,ymax)
  97.          For x=0 to xmax
  98.             For y=0 to ymax
  99.                QUICKSQR(x,y)=SQR(x*x+y*y)
  100.             Next y
  101.          Next x
  102.          Repeat
  103.             If QUICKSQR(Abs(x),Abs(y))=10 Then blah blah blah
  104.          Until Something
  105.  
  106. 6. Get yourself a fast extension, such as AMCAF or Turbo Plus. This will
  107. L  only speed things up where an extension command replaces an internal
  108.    command with a faster one - Easylife and AMCAF will do this for many
  109.    string operations and, AMCAF, Turbo and Powerbobs do it for graphics.
  110.  
  111.    Eg.
  112.       Don't use :
  113.          Plot x,y,c
  114.       Use this instead :
  115.          Turbo Plot x,y,c (for AMCAF)
  116.       or F Plot x,y,c (for Turbo Plus)
  117.  
  118.    Many extensions can be found on Aminet (FTP from wuarchive.wustl.edu
  119.    in systems/amiga/aminet/dev/amos).
  120.  
  121. 7. Use < and > instead of <= and >= whenever possible. They are slightly
  122. S  faster. Strange, but true.
  123.  
  124.    Eg.
  125.       Don't use :
  126.          If n<=10 Then blah
  127.       Use this instead :
  128.          If n<11 Then blah
  129.  
  130.    But, don't use this kind of thing:
  131.       A=10
  132.       If B>A-1 Then etc
  133.    ...instead of:
  134.       A=10
  135.       If B>=A Then etc
  136.  
  137. 8. Don't do stuff like If n=True, If n=False, or If n<>0. Also, using =False
  138. M  instead of =0 is faster.
  139.  
  140.    Eg.
  141.       Don't use :
  142.          If a=True or b=False or c<>0 Then blah blah
  143.       Use this instead :
  144.          If a or Not(b) or c Then blah blah
  145.  
  146.    But ONLY do this if you are sure b is a boolean value. "Not" simply
  147.    bitflips an integer so Not -1 is 0, but Not 2 is $FFFFFFFE.
  148.  
  149.    AMOSPro is rather buggy with the Not() command, so you may have to
  150.    experiment a bit.
  151.  
  152. 9. Never use floating points. Use integers multiplied by a power of 2. You
  153. L  can actually decide what sort of precision you want in your decimal places
  154.    and then multiply them out. For example, if you decide on about 2 point
  155.    accuracy, you can multiply all your values by 128 (2^7, close enough to
  156.    100) and then do the calculations. When you have the results simply divide
  157.    by 128 to get the required result.
  158.  
  159.    Eg.
  160.       Don't use :
  161.          x#=x#*1.5
  162.          Plot x#,100
  163.       Use this instead :
  164.          x=x*(3*128) : Rem Same as x=x*(1.5*256)
  165.                        Rem 3*128 is calculated at compilation time
  166.          Plot X/256,100
  167.  
  168. 10. Use assembler procedures for inner loops. Beware though, it does take
  169. V   a small amount of CPU time to jump to an assembler procedure, so with
  170.     small routines, it's simply not worth it.
  171.  
  172. 11. Use "Copper Off" to disable the screen while doing intense communication.
  173. S   The copper then stops stealing clock cycles from the processor (Unlike
  174.     Multi No and such instructions, this really does work). Use "Copper On"
  175.     to re-enable the normal system.
  176.  
  177. 12. Move invarient statement outside loops (Standard optimising compiler
  178. V   stuff).
  179.  
  180.     Eg.
  181.        If you have something like this :
  182.           Repeat
  183.              If x<a*20 Then do something groovy
  184.           Until something
  185.        If the rest of the loop does not modify a, this can become :
  186.           temp=a*20
  187.           Repeat
  188.              If x<temp Then do something groovy
  189.           Until something
  190.  
  191. 13. Use global variables to return parameters from procedures, rather than
  192. S   Param.
  193.  
  194.     Eg.
  195.        Don't use :
  196.           _HELLO[10,20] : pram=Param : Print pram
  197.           Procedure _HELLO[x,y]
  198.              temp=0
  199.              For n=x To y
  200.                 If a(n)=0 Then temp=n : Exit
  201.              Next n
  202.           End Proc[temp]
  203.        Use this instead :
  204.           Global pram
  205.           _HELLO[10,20] : Print pram
  206.           Procedure _HELLO[x,y]
  207.              pram=0
  208.              For n=x To y
  209.                 If a(n)=0 Then pram=n : Pop Proc
  210.              Next N
  211.           End Proc
  212.  
  213.     However, don't do things like this, which are actually slower.
  214.  
  215.     Don't do:
  216.        _HELLO[10,20] : Print A
  217.        Procedure _HELLO[X,Y]
  218.           Shared A
  219.           A=X*Y
  220.        End Proc
  221.     Do this:
  222.        _HELLO[10,20] : Print Param
  223.        Procedure _HELLO[X,Y]
  224.        End Proc[X*Y]
  225.  
  226. 14. Use Cls col,x1,y1 To x2,y2 instead of Bar x1,y1 To x2,y2.
  227. M   Note : Use R Bar in Turbo instead if possible.
  228.  
  229. 15. Use Polyline to draw boxes instead of Box.
  230. S   Note : Use R Box in Turbo instead if possible.
  231.  
  232.     Eg.
  233.        Don't use :
  234.           Box 10,10 To 10,10
  235.        Use this instead :
  236.           Polyline 10,10 To 20,10 To 20,20 To 10,20
  237.  
  238. 16. Use single dimensional arrays instead of two dimensional ones if
  239. S   possible.
  240.  
  241.     Eg.
  242.        Don't use :
  243.           Dim A(2,100)
  244.        Use this instead :
  245.           Dim A0(100),A1(100),A2(100)
  246.  
  247. 17. Use N=N+A instead of using Inc, Dec or Add. Although the manual claims
  248. S   they are faster, when using the AMOSPro Compiler, they actually turn
  249.     out slightly slower.
  250.  
  251.     Eg.
  252.        Don't use :
  253.           Inc a : Dec b : Add c,10
  254.        Use this instead :
  255.           a=a+1 : b=b-1 : c=c+10
  256.  
  257.     Note : Although Add is slower in it's short form, the full version
  258.     with the base To top part is faster than the equivilant code.
  259.  
  260.     This only applies to standard variables - DON'T use this with arrays!
  261.  
  262. 18. Use a Repeat / Until loop instead of a For / Next loop.
  263. S
  264.     Eg.
  265.        Don't use :
  266.           For n=0 to 10
  267.              (code)
  268.           Next n
  269.        Use this instead :
  270.           n=0
  271.           Repeat
  272.              (code)
  273.              n=n+1
  274.           Until n=11 : Rem MUST be one more than with the original For
  275.  
  276. 19. Use Peek(Varptr(a$)+x-1) instead of Asc(Mid$(a$,x,1)) and
  277. L   Poke Varptr(a$)+x-1,Asc(b$) instead of Mid$(a$,x,1)=b$.
  278.  
  279.     Eg.
  280.        Don't use :
  281.           A=Asc(Mid$(a$,3,1))
  282.           Mid$(a$,6,1)=b$
  283.        Use this instead :
  284.           A=Peek(Varptr(a$)+2)
  285.           Poke Varptr(a$)+5,Asc(b$) : Rem Asc(b$) could be predefined
  286.  
  287.     Note : This is just under three times as fast!
  288.  
  289. 20. Use Fill to clear an array to a certain value, rather than the
  290. L   equivilant For / Next loop.
  291.  
  292.     Eg.
  293.        Don't use :
  294.           For n=0 to 1000
  295.              A(n)=27
  296.           Next n
  297.        Use this instead :
  298.           Fill Varptr(A(0)) To Varptr(A(1000)),27
  299.  
  300. 21. Use "If condition Then code" instead of "If condition : code : End If",
  301. S   if the code is short.
  302.  
  303.     Eg.
  304.        Don't use :
  305.           If a=2
  306.              la-de-da
  307.           End If
  308.        Use this instead :
  309.           If a=2 Then la-de-da
  310.  
  311. 22. Use subroutines instead of procedures. Although they're messier, they are
  312. L   several times faster!
  313.  
  314.     Eg.
  315.        Don't use :
  316.           _SOMETHING
  317.           Procedure _SOMETHING
  318.              Code
  319.           End Proc
  320.        Use this instead :
  321.           Gosub _SOMETHING
  322.           _SOMETHING:
  323.              Code
  324.           Return
  325.  
  326. 23. This routine is for making the string 1 character shorter. It may be
  327. M   helpful in an program to replace the input command.
  328.  
  329.     Eg.
  330.        Don't use :
  331.           S$=Space$(1000)
  332.           For X=1 To 1000
  333.              S$=Left$(S$,Len(S$)-1)
  334.           Next X
  335.        Use this instead :
  336.           S$=Space$(1000)
  337.           POS=Varptr(S$) : Rem Put this statement inside the loop if you
  338.                            Rem do any standard string operations.
  339.           For X=1 To 1000
  340.              Doke POS-2,Deek(POS)-1
  341.           Next X
  342.  
  343.     Note : This routine could be rather risky, as it is done outside the AMOS
  344.     string handling system.
  345.  
  346. 24. Don't use Start(BANK), Screen Width or Screen Height in a routine that
  347. S   must be fast. In fact, do the same with any AMOS variable that won't
  348.     change in the loop.
  349.  
  350.     Eg.
  351.        Don't use :
  352.           For X=1 To 10000
  353.              PE=Peek(Start(10)+X)
  354.           Next X
  355.        Use this instead :
  356.           ST=Start(BANK)
  357.           For X=1 To 10000
  358.              PE=Peek(ST+X)
  359.           Next X
  360.  
  361. 25. Don't use Chr$(code) in routines but replace them with a string.
  362. S
  363.     Eg.
  364.        Don't use :
  365.           I=Instr(ST$,Chr$(0))
  366.        Use this instead :
  367.           C0$=Chr$(0)      : Rem at the beginning of your prog
  368.           I=Instr(ST$,C0$) : Rem in the routine
  369.  
  370. 26. A quasi-optimisation: Use "n=Free" at points where you don't care about
  371. V   the speed, to reduce the chances of the AMOS string garbage collector
  372.     being called when you do care about the speed. This will only have an
  373.     effect when strings are used in the routine.
  374.  
  375. 27. Don't use parameters in Def Fns. As functions are local to procedures,
  376. M   any variables used, will be known in the function.
  377.  
  378.     Eg.
  379.        Don't use :
  380.           Def Fn C(x,y)=(x*y*y+x) MOD 16
  381.           For x=0 To 10
  382.              For y=0 To 10
  383.                 Plot x,y,Fn C(x,y)
  384.              Next y
  385.           Next x
  386.        Use this instead :
  387.           Def Fn C=(x*y*y+x) MOD 16
  388.           For x=0 To 10
  389.              For y=0 To 10
  390.                 Plot x,y,Fn C
  391.              Next y
  392.           Next x
  393.  
  394. 28. Use as few brackets in equations and If structures as possible.
  395. S
  396.     Eg.
  397.        Don't use :
  398.           A=(B*C)-(D*E)-(F+G)
  399.           C=(A=2 or B=100)
  400.        Use this instead :
  401.           A=B*C-D*E-F-G
  402.           C=A=2 or B=100
  403.  
  404. 29. Use the value of expressions, rather than testing what they mean.
  405. M
  406.     Eg.
  407.        Don't use :
  408.           If Jup(1)
  409.              Y=Y-1
  410.           End If
  411.           If Jdown(1)
  412.              Y=Y+1
  413.           End If
  414.        Use this instead :
  415.           Y=Y+Jup(1)-Jdown(1)
  416.  
  417.     Remember : If it is True, -1 is returned, otherwise 0 is returned.
  418.  
  419.     The Turbo (Plus) extension has a useful command called "Texp" which
  420.     returns specified values for True and False.
  421.  
  422. 30. The fastest way to display a map, using a few of the above tips :
  423. M
  424.        ' This is the slow way, that I've seen in multiple sources of games
  425.        For Y=0 To FHV
  426.           For X=0 To FWV
  427.              Paste Icon 16+X*16,16+Y*16,Peek((FPOSY+Y)*FW+Start(BLS1)+FPOSX)+1
  428.           Next X
  429.        Next Y
  430.  
  431.        ' Now my quick version... Note that the start(bank)
  432.        ' is placed in front of the routine.
  433.        ' FHV   = Field Height View
  434.        ' FHV   = Field Width  View
  435.        ' FPOSX = Field POSition X (Where the player is looking in the map)
  436.        ' FPOSY = Field POSition Y
  437.        POS=Start(BLS1)+FPOSX
  438.        For Y=0 To FHV
  439.           MPY=(FPOSY+Y)*FW+POS
  440.           SPY=16+Y*16
  441.           For X=0 To FWV
  442.              ' Using a Turbo Plus extension command
  443.              F Paste Icon 16+X*16,SPY,Peek(MPY+X)+1
  444.           Next X
  445.        Next Y
  446.  
  447.  
  448.  
  449. Try various ways of writing code to see if you can find the quickest.
  450. Something like this is a nice way :
  451.  
  452.    Timer=0
  453.    For n=0 To 10000
  454.       Unoptimised code
  455.    Next n
  456.    Print "Time for unoptimised code :";Timer
  457.  
  458.    Timer=0
  459.    For n=0 To 10000
  460.       Optimised code
  461.    Next n
  462.    Print "Time for optimised code :";Timer
  463.  
  464. If you find any general purpose tips, send them to me (at bwyatt@paston.co.uk)
  465. and I'll add them to the list!
  466.  
  467. If you want proof that these tips do work, then take a look at two of my
  468. recent games, Borisball and Knockout 2. Apart from being tremendously good
  469. fun, they demonstrate how the AMOS speed limit can be broken! ;-) Their
  470. Aminet positions are:
  471.    game/demo/BorisBall.lha
  472.    game/2play/KnockOut2.lha
  473.